package org.wesc.boot.service.system.menu;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.wesc.boot.dao.entity.Menu;
import org.wesc.boot.dao.entity.RoleMenu;
import org.wesc.boot.dao.mapper.MenuMapper;
import org.wesc.boot.dao.mapper.RoleMenuMapper;
import org.wesc.boot.dao.model.MenuQueryModel;
import org.wesc.boot.dao.querymapper.MenuQueryMapper;
import org.wesc.boot.service.system.router.Tree;
import org.wesc.boot.service.utils.TreeUtil;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 菜单服务
 *
 * @author Wesley
 */
@Slf4j
@Service
public class MenuAdvanceService {

    /**
     * 按钮
     */
    private static final String TYPE_BUTTON = "1";

    private final MenuMapper menuMapper;

    private final MenuQueryMapper menuQueryMapper;

    private final RoleMenuMapper roleMenuMapper;

    @Autowired
    public MenuAdvanceService(MenuMapper menuMapper, MenuQueryMapper menuQueryMapper, RoleMenuMapper roleMenuMapper) {
        this.menuMapper = menuMapper;
        this.menuQueryMapper = menuQueryMapper;
        this.roleMenuMapper = roleMenuMapper;
    }

    /**
     * 查询用户菜单树的所需权限
     */
    public List<Menu> findUserMenuPerms(String username) {
        return menuQueryMapper.findUserMenuPerms(username);
    }

    /**
     * 查询用户菜单，用于构建菜单树
     */
    public List<Menu> findUserMenus(String username) {
        return this.menuQueryMapper.findUserMenus(username);
    }

    /**
     * 查询菜单，并构建菜单树
     */
    public Map<String, Object> findMenus(MenuQueryModel menuQueryModel) {
        Map<String, Object> result = new HashMap<>(16);
        try {
            LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
            findMenuCondition(queryWrapper, menuQueryModel);
            List<Menu> menus = menuMapper.selectList(queryWrapper);

            List<Tree<Menu>> trees = new ArrayList<>();
            List<String> ids = new ArrayList<>();
            buildTrees(trees, menus, ids);

            result.put("ids", ids);
            if (StringUtils.equals(menuQueryModel.getType(), TYPE_BUTTON)) {
                result.put("rows", trees);
            } else {
                Tree<Menu> menuTree = TreeUtil.build(trees);
                result.put("rows", menuTree);
            }

            result.put("total", menus.size());
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
            result.put("rows", null);
            result.put("total", 0);
        }
        return result;
    }


    /**
     * 获取菜单列表
     */
    public List<Menu> findMenuList(MenuQueryModel menuQueryModel) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        findMenuCondition(queryWrapper, menuQueryModel);
        queryWrapper.orderByAsc(Menu::getMenuId);
        return this.menuMapper.selectList(queryWrapper);
    }

    /**
     * 根据角色ID查找所有的菜单
     */
    public List<RoleMenu> findMenuByRoleId(long roleId) {
        return roleMenuMapper.selectList(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, roleId));
    }

    /**
     * 创建菜单
     */
    @Transactional(rollbackFor = Exception.class)
    public void createMenu(Menu menu) {
        menu.setCreateTime(LocalDateTime.now());
        setMenu(menu);
        menuMapper.insert(menu);
    }

    /**
     * 更新菜单
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(Menu menu) {
        menu.setModifyTime(LocalDateTime.now());
        setMenu(menu);
        UpdateWrapper<Menu> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq(Menu.MENU_ID, menu.getMenuId());
        menuMapper.update(menu, updateWrapper);

        // 查找与这些菜单/按钮关联的用户
        this.menuQueryMapper.findUserIdsByMenuId(menu.getMenuId());
    }

    /**
     * 批量删除菜单及其递归子菜单
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteMenus(Long[] menuIds) {
        for (long menuId : menuIds) {
            // 递归删除这些菜单/按钮
            recursionDeleteMenu(menuId);

            // 删除菜单关联的role-menu关联关系
            roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getMenuId, menuId));
        }
    }

    /**
     * 递归删除菜单及其子菜单
     */
    public void recursionDeleteMenu(long menuId){
        // 删除当前菜单
        Map<String, Object> columnMap = new HashMap<>(16);
        columnMap.put(Menu.MENU_ID, menuId);
        menuMapper.deleteByMap(columnMap);
        columnMap.clear();

        // 查找当前菜单的直属子菜单
        List<Menu> subMenus = menuQueryMapper.findChildrenMenus(menuId);
        if (subMenus != null && subMenus.size() > 0) {
            for(Menu menu : subMenus) {
                recursionDeleteMenu(menu.getMenuId());
            }
        }
    }

    /**
     * 构建菜单树
     */
    private void buildTrees(List<Tree<Menu>> trees, List<Menu> menus, List<String> ids) {
        menus.forEach(menu -> {
            ids.add(menu.getMenuId().toString());
            Tree<Menu> tree = new Tree<>();
            tree.setId(menu.getMenuId().toString());
            tree.setKey(tree.getId());
            tree.setParentId(menu.getParentId().toString());
            tree.setText(menu.getMenuName());
            tree.setTitle(tree.getText());
            tree.setIcon(menu.getIcon());
            tree.setComponent(menu.getComponent());
            tree.setCreateTime(menu.getCreateTime());
            tree.setModifyTime(menu.getModifyTime());
            tree.setPath(menu.getPath());
            tree.setOrder(menu.getOrderNum());
            tree.setPermission(menu.getPerms());
            tree.setType(menu.getType());
            trees.add(tree);
        });
    }

    /**
     * 设置菜单
     */
    private void setMenu(Menu menu) {
        if (menu.getParentId() == null) {
            menu.setParentId(0L);
        }
        if (TYPE_BUTTON.equals(menu.getType())) {
            menu.setPath(null);
            menu.setIcon(null);
            menu.setComponent(null);
        }
    }

    /**
     * 构建菜单查询条件
     */
    private void findMenuCondition(LambdaQueryWrapper<Menu> queryWrapper, MenuQueryModel menu) {
        if (StringUtils.isNotBlank(menu.getMenuName())) {
            queryWrapper.eq(Menu::getMenuName, menu.getMenuName());
        }
        if (StringUtils.isNotBlank(menu.getType())) {
            queryWrapper.eq(Menu::getType, menu.getType());
        }
        if (StringUtils.isNotBlank(menu.getCreateTimeFrom()) && StringUtils.isNotBlank(menu.getCreateTimeTo())) {
            queryWrapper
                    .ge(Menu::getCreateTime, menu.getCreateTimeFrom())
                    .le(Menu::getCreateTime, menu.getCreateTimeTo());
        }
    }

}
